package cn.gok.springsecuritydemo05.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Calendar;
import java.util.Date;
import java.util.Map;

/**
 * @author: chen fan
 * @since: 2022/11/23 10:23
 * @description:
 */
@Component
public class JWTUtil {

    /**
     * 定义秘钥
     */
    @Value("${jwt.config.secret}")
    private String secret;

    @Value("${jwt.config.tokenExpireSeconds}")
    private int tokenExpireSeconds;




    /**
     * 生成Token
     * @param payloadInfo   要存放的信息
     * @param tokenExpireSeconds token过期时间
     * @return
     */
    public  String createToken(Map<String,Object> payloadInfo, int tokenExpireSeconds){
        // withClaim存数据时，value值的类型： 数值、字符串、布尔值、日期、数组（String Long、Integer）


        JWTCreator.Builder builder = JWT.create();

        //存入简单的用户信息
        for (Map.Entry<String, Object> entry : payloadInfo.entrySet()) {
            setPayloadInfo(builder,entry.getKey(),entry.getValue());
        }
        //设置默认过期时间
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.SECOND,tokenExpireSeconds);
        builder.withExpiresAt(instance.getTime());

        //创建token并返回
        return builder.sign(Algorithm.HMAC256(secret));
    }

    public  String createToken(Map<String,Object> payloadInfo){
        return  createToken(payloadInfo,1800);
    }

    /**
     * 对token进行校验的方法，如果没有抛出任何异常，则说明验证通过
     * @param token
     */
    public void verify(String token){
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(secret)).build();
       jwtVerifier.verify(token);
    }

    /**
     * 从解析后的token中获取数据, 如果数据时简单类型的，使用此方法
     * @param token： jwtToken
     * @param key     在设置withClaim时的key
     * @param clazz   要获取的数据的类型
     * @param <T>
     * @return
     */
    public <T> T getValue(String token,String key,Class<T> clazz){
        DecodedJWT decodedJWT = JWT.require(Algorithm.HMAC256(secret)).build().verify(token);
        return decodedJWT.getClaim(key).as(clazz);
    }

    /**
     * 从解析后的token中获取数据, 如果数据是数组类型，调用此方法
     * @param token
     * @param key
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> T[] getArrayValue(String token,String key,Class<T> clazz){
        DecodedJWT decodedJWT = JWT.require(Algorithm.HMAC256(secret)).build().verify(token);
       return decodedJWT.getClaim(key).asArray(clazz);
    }


    private void setPayloadInfo(JWTCreator.Builder builder,String key,Object value){
        Class<?> aClass = value.getClass();
        if (aClass.equals(String.class)){
            builder.withClaim(key,(String) value);
        }else if (aClass.equals(Boolean.class)){
            builder.withClaim(key,(Boolean) value);
        }else if (aClass.equals(Date.class)){
            builder.withClaim(key,(Date) value);
        }else if (aClass.equals(Long.class)){
            builder.withClaim(key,(Long) value);
        }else if (aClass.equals(Integer.class)){
            builder.withClaim(key,(Integer) value);
        }else if (aClass.equals(Double.class)){
            builder.withClaim(key,(Double) value);
        }else if (aClass.equals(String[].class)){
            builder.withArrayClaim(key,(String[]) value);
        }else if (aClass.equals(Long[].class)){
            builder.withArrayClaim(key,(Long[]) value);
        }else if (aClass.equals(Integer[].class)){
            builder.withArrayClaim(key,(Integer[]) value);
        }else {
            throw new IllegalArgumentException("存入token中的数据不合法，存入值的类型应为：String、Boolean、Long、Integer、Double、" +
                    "Date、String[]、Long[]、Integer[] 中的任意一种，但是你传入的值的类型为： " + aClass );
        }
    }
}
